#include "common/elements/element_maker.h"

#include "common/log/log.h"

#include "common/more/json.h"
#include "common/more/uuid.h"

#include "server.h"

namespace Api
{

std::string Server::getIdsCall(
    const std::string& requestBody,
    const GetIdsFunction& function
)
{
    // Получение аргументов
    const auto requestJson = Common::stringToJson(requestBody);
    const auto sessionUuid = Uuids::stringToUuid(requestJson["sessionUuid"].get<std::string>());
    const auto elementType = Elements::ElementType(requestJson["elementType"].get<unsigned>());
    // TODO : Реализовать получение filterOptional
    // const auto filterOptional = requestJson["filter"].get<std::string>();
    const std::string filter = {};

    // Выполнение функции
    const auto ids = function(sessionUuid, elementType, filter);

    // Формирование результата
    Common::Json responseJson;
    responseJson["ids"] = Common::Json(ids);
    return Common::jsonToString(responseJson);
}

std::string Server::getElementsCall(
    const std::string& requestBody,
    const GetElementsFunction& function
)
{
    // Получение аргументов
    const auto requestJson = Common::stringToJson(requestBody);
    const auto sessionUuid = Uuids::stringToUuid(requestJson["sessionUuid"].get<std::string>());
    const auto elementType = Elements::ElementType(requestJson["elementType"].get<unsigned>());
    const auto ids = requestJson["ids"].get<std::vector<unsigned>>();

    // Выполнение функции
    const auto elements = function(sessionUuid, elementType, ids);

    // Формирование результата
    auto elementsJson = Common::Json::array();
    for (const auto element : elements)
        elementsJson.push_back(element->toJson());

    Common::Json responseJson;
    responseJson["elements"] = elementsJson;
    return Common::jsonToString(responseJson);
}

std::string Server::addElementCall(
    const std::string& requestBody,
    const AddElementFunction& function
)
{
    // Получение аргументов
    const auto requestJson = Common::stringToJson(requestBody);
    const auto sessionUuid = Uuids::stringToUuid(requestJson["sessionUuid"].get<std::string>());
    std::shared_ptr<Elements::Element> element(Elements::fromJson(requestJson["element"]));

    // Выполнение функции
    const unsigned elementId = function(sessionUuid, element);

    // Формирование результата
    Common::Json responseJson;
    responseJson["success"] = bool(0 != elementId);
    responseJson["id"] = elementId;
    return Common::jsonToString(responseJson);
}

std::string Server::setElementCall(
    const std::string& requestBody,
    const SetElementFunction& function
)
{
    // Получение аргументов
    const auto requestJson = Common::stringToJson(requestBody);
    const auto sessionUuid = Uuids::stringToUuid(requestJson["sessionUuid"].get<std::string>());
    std::shared_ptr<Elements::Element> element(Elements::fromJson(requestJson["element"]));

    // Выполнение функции
    const bool success = function(sessionUuid, element);

    // Формирование результата
    Common::Json responseJson;
    responseJson["success"] = success;
    return Common::jsonToString(responseJson);
}

std::string Server::delElementCall(
    const std::string& requestBody,
    const DelElementFunction& function
)
{
    // Получение аргументов
    const auto requestJson = Common::stringToJson(requestBody);
    const auto sessionUuid = Uuids::stringToUuid(requestJson["sessionUuid"].get<std::string>());
    const auto elementType = Elements::ElementType(requestJson["elementType"].get<unsigned>());
    const auto id = requestJson["id"].get<unsigned>();

    // Выполнение функции
    const bool success = function(sessionUuid, elementType, id);

    // Формирование результата
    Common::Json responseJson;
    responseJson["success"] = success;
    return Common::jsonToString(responseJson);
}

std::string Server::hasChangesCall(
    const std::string& requestBody,
    const HasChangedFunction& function
)
{
    // Получение аргументов
    const auto requestJson = Common::stringToJson(requestBody);
    const auto sessionUuid = Uuids::stringToUuid(requestJson["sessionUuid"].get<std::string>());

    // Выполнение функции
    const auto changes = function(sessionUuid);

    // Формирование результата
    auto changesJson = Common::Json::array();
    for (const auto& entry : changes)
    {
        Common::Json changeJson;
        changeJson["elementType"] = unsigned(entry.first);
        changeJson["ids"] = Common::Json(entry.second);
        changesJson.push_back(changeJson);
    }
    Common::Json responseJson;
    responseJson["changes"] = changesJson;
    return Common::jsonToString(responseJson);
}

std::string Server::loginCall(
    const std::string& requestBody,
    const LoginFunction& function
)
{
    // Получение аргументов
    const auto requestJson = Common::stringToJson(requestBody);
    const auto user = requestJson["user"].get<std::string>();
    const auto password = requestJson["password"].get<std::string>();

    // Выполнение функции
    const auto result = function(user, password);

    // Формирование результата
    Common::Json responseJson;
    responseJson["sessionUuid"] = Uuids::uuidToString(result.m_sessionUuid);
    responseJson["id"] = result.m_userId;
    return Common::jsonToString(responseJson);
}

std::string Server::logoutCall(
    const std::string& requestBody,
    const LogoutFunction& function
)
{
    // Получение аргументов
    const auto requestJson = Common::stringToJson(requestBody);
    const auto sessionUuid = Uuids::stringToUuid(requestJson["sessionUuid"].get<std::string>());
    const auto user = requestJson["user"].get<std::string>();

    // Выполнение функции
    const bool success = function(sessionUuid, user);

    // Формирование результата
    Common::Json responseJson;
    responseJson["success"] = success;
    return Common::jsonToString(responseJson);
}

} // namespace Api
